/**
 *******************************************************************************
 * @file  usb_dev_audio_class.h
 * @brief Audio class for USB device
 @verbatim
   Change Logs:
   Date             Author          Notes
   2021-03-29       Linsq           First version
 @endverbatim
 *******************************************************************************
 * Copyright (C) 2020, Huada Semiconductor Co., Ltd. All rights reserved.
 *
 * This software component is licensed by HDSC under BSD 3-Clause license
 * (the "License"); You may not use this file except in compliance with the
 * License. You may obtain a copy of the License at:
 *                    opensource.org/licenses/BSD-3-Clause
 *
 *******************************************************************************
 */

/*******************************************************************************
 * Include files
 ******************************************************************************/
#include "usb_dev_audio_class.h"
#include "usb_dev_audio_out_itf.h"
#include "usb_dev_audio_in_itf.h"
#include "codec.h"
#include "string.h"
/*********************************************
   AUDIO Device library callbacks
 *********************************************/
void usb_dev_audio_init(void *pdev);
void usb_dev_audio_deinit(void *pdev);
uint8_t usb_dev_audio_setup(void *pdev, USB_SETUP_REQ *req);
void usb_dev_audio_ctrlout(void *pdev);
void usb_dev_audio_datain(void *pdev, uint8_t epnum);
void usb_dev_audio_dataout(void *pdev, uint8_t epnum);
uint8_t usb_dev_audio_sof(void *pdev);
void usb_dev_audio_out_incplt(void *pdev);
void usb_dev_audio_in_incplt(void *pdev);

void audio_getcurrent_req(void *pdev, USB_SETUP_REQ *req);
void audio_setcurrent_req(void *pdev, USB_SETUP_REQ *req);
uint8_t *usb_dev_audio_getcfgdesc(uint16_t *length);

/* Main Buffer for Audio Data Out transfers and its relative pointers */
uint8_t  IsocOutBuff [TOTAL_OUT_BUF_SIZE * 2];
uint8_t* IsocOutWrPtr = IsocOutBuff;              //Save the data received from USB to IsocOutBuff
uint8_t* IsocOutRdPtr = IsocOutBuff;              //Send the data from IsocOutBuff to I2S

uint32_t  IsocInBuff[TOTAL_IN_BUF_SIZE * 1];      //Used to save data from I2S
uint32_t* IsocInWrPtr = IsocInBuff;               //Used to send the data to USB from IsocInBuff
uint32_t* IsocInRdPtr = IsocInBuff;
uint16_t  IsocInWrCnt, IsocInRdCnt;
#define  REC_IDLE    0                            //The recorder is idle
#define  REC_RUN     1                            //The recorder is running
#define  REC_STOP    2                            //The recorder is stop
uint8_t  rec_state = REC_IDLE;                    //The running state of the recorder
uint16_t in_exit;                                 //This is used to judge if whether recorder exists or not.
uint16_t InBuffDummy[AUDIO_IN_PACKET];            // This dummy buffer with 0 values will be sent when there is no availble data

/* Main Buffer for Audio Control Requests transfers and its relative variables */
uint8_t  AudioCtl[64];
uint8_t  AudioCtlCmd = 0;
uint32_t AudioCtlLen = 0;
uint8_t  AudioCtlUnit = 0;
uint8_t  AudioTrgtEpt = 0;

uint32_t PlayFlag = 0;
uint32_t RecFlag  = 0;
static __IO uint32_t  usbd_audio_AltSet = 0;
static uint8_t usbd_audio_CfgDesc[AUDIO_CONFIG_DESC_SIZE];

/* AUDIO interface class callbacks structure */
usb_dev_class_func  AUDIO_cb = 
{
  usb_dev_audio_init,
  usb_dev_audio_deinit,
  usb_dev_audio_setup,
  NULL, 
  usb_dev_audio_ctrlout,
  usb_dev_audio_getcfgdesc,
  usb_dev_audio_sof,  
  usb_dev_audio_datain,
  usb_dev_audio_dataout,
  usb_dev_audio_in_incplt,
  usb_dev_audio_out_incplt   
    
};
/* USB AUDIO device Configuration Descriptor */
static uint8_t usbd_audio_CfgDesc[AUDIO_CONFIG_DESC_SIZE] =
{
    /* Configuration Descriptor */
    9,                                        /* bLength */
    USB_CFG_DESCRIPTOR_TYPE,                  /* bDescriptorType */
    LOBYTE(AUDIO_CONFIG_DESC_SIZE),           /* wTotalLength: low byte */
    HIBYTE(AUDIO_CONFIG_DESC_SIZE),           /* wTotalLength: high byte */
    0x03,                                     /* bNumInterfaces - Interface 0, Interface 1 (Microphone), Interface 2 (Speaker), Interface 3 (HID) */
    0x01,                                     /* bConfigurationValue */
    0x00,                                     /* iConfiguration */
    0xc0,                                     /* bmAttributes */
    0x32,                                     /* Max power */
    /* 9 byte */
    
    /* Interface Descriptor (Audio Class) */
    0x09,                                     /* bLength */
    USB_INTERFACE_DESCRIPTOR_TYPE,            /* bDescriptorType */
    0x00,                                     /* bInterfaceNumber */
    0x00,                                     /* bAlternateSetting */
    0x00,                                     /* bNumEndpoints */
    USB_DEVICE_CLASS_AUDIO,                   /* bInterfaceClass:AUDIO */
    AUDIO_SUBCLASS_AUDIOCONTROL,              /* bInterfaceSubClass:AUDIOCONTROL */
    AUDIO_PROTOCOL_UNDEFINED,                 /* bInterfaceProtocol */
    0x00,                                     /* iInterface */
    /* 9 byte */

    /* Audio Control Interface Header Descriptor */
    0x0A,                                          /* bLength */
    AUDIO_INTERFACE_DESCRIPTOR_TYPE,               /* bDescriptorType:CS_INTERFACE */
    AUDIO_CONTROL_HEADER,                          /* bDescriptorSubType:HEADER */
    0x00, 0x01,                                    /* bcdADC:1.0 */
    0x3d, 0x00,                                    /* wTotalLength
                           Audio Control Interface Header Descriptor  (0x0A)
                           Microphone - Audio Control
                             Audio Control Input Terminal Descriptor  (0x09)
                             Audio Control Output Terminal Descriptor (0x0C)
                           Speaker - Audio Control
                             Audio Control Input Terminal Descriptor  (0x0C)
                             Audio Control Feature Unit Descriptor    (0x09)
                             Audio Control Output Terminal Descriptor (0x09)
                             0x0A + (0x09 + 0x0C) + (0x0C + 0x09 + 0x09) = 0x3D*/
    0x02,                                          /* bInCollection */
    0x01,                                          /* baInterfaceNr(1) - Microphone */
    0x02,                                          /* baInterfaceNr(2) - Speaker */
    /* 10 byte */
    
    /* Audio Control Input Terminal Descriptor - Microphone (Terminal ID 4) */
    0x0C,                                          /* bLength */
    AUDIO_INTERFACE_DESCRIPTOR_TYPE,               /* bDescriptorType:CS_INTERFACE */
    AUDIO_CONTROL_INPUT_TERMINAL,                  /* bDescriptorSubType:INPUT_TERMINAL*/
    MIC_IT_ID,                                     /* bTerminalID*/
    0x01,0x02,                                     /* wTerminalType: Microphone 0x0201 */
    0x00,                                          /* bAssocTerminal*/
    0x02,                                          /* bNrChannels : a number that specifies how many logical audio channels are present in the cluster */
    0x03, 0x00,                                    /* wChannelConfig: a bit field that indicates which spatial locations are present in the cluster.
                           The bit allocations are as follows:
                             D0: Left Front (L)
                             D1: Right Front (R)
                             D2: Center Front (C)
                             D3: Low Frequency Enhancement (LFE)
                             D4: Left Surround (LS)
                             D5: Right Surround (RS)
                             D6: Left of Center (LC)
                             D7: Right of Center (RC)
                             D8: Surround (S)
                             D9: Side Left (SL)
                             D10: Side Right (SR)
                             D11: Top (T)
                             D15..12: Reserved*/
    0x00,                                          /* iChannelNames*/
    0x00,                                          /* iTerminal*/
    /* 12 byte */

    /* Audio Control Output Terminal Descriptor - Microphone (Terminal ID 2 - Source ID 5) */
    0x09,                                          /* bLength */
    AUDIO_INTERFACE_DESCRIPTOR_TYPE,               /* bDescriptorType:CS_INTERFACE */
    AUDIO_CONTROL_OUTPUT_TERMINAL,                 /* bDescriptorSubType:OUTPUT_TERMINAL */
    MIC_OT_ID,                                     /* bTerminalID */
    0x01,0x01,                                     /* wTerminalType: 0x0101 usb streaming */
    MIC_IT_ID,                                     /* bAssocTerminal */
    MIC_IT_ID,                                     /* bSourceID */
    0x00,                                          /* iTerminal */
    /* 9 byte */

    /* Audio Control Input Terminal Descriptor - Speaker (Terminal ID 1) */
    0x0C,               /* bLength */
    0x24,               /* bDescriptorType:CS_INTERFACE */
    0x02,               /* bDescriptorSubType:INPUT_TERMINAL */
    SPK_IT_ID,          /* bTerminalID */
    0x01,0x01,          /* wTerminalType: USB streaming */
    0x00,               /* bAssocTerminal */
    0x02,               /* bNrChannels : a number that specifies how many logical audio channels are present in the cluster */
    0x03,0x00,          /* wChannelConfig: a bit field that indicates which spatial locations are present in the cluster.
                           The bit allocations are as follows:
                             D0: Left Front (L)
                             D1: Right Front (R)
                             D2: Center Front (C)
                             D3: Low Frequency Enhancement (LFE)
                             D4: Left Surround (LS)
                             D5: Right Surround (RS)
                             D6: Left of Center (LC)
                             D7: Right of Center (RC)
                             D8: Surround (S)
                             D9: Side Left (SL)
                             D10: Side Right (SR)
                             D11: Top (T)
                             D15..12: Reserved*/
    0x00,                /* iChannelNames */
    0x00,                /* iTerminal */
    /* 12 byte */
    
    /* USB Speaker Audio Feature Unit Descriptor */
    0x09,                                 /* bLength */
    AUDIO_INTERFACE_DESCRIPTOR_TYPE,      /* bDescriptorType */
    AUDIO_CONTROL_FEATURE_UNIT,           /* bDescriptorSubtype */
    SPK_FU_ID,                            /* bUnitID */
    SPK_IT_ID,                            /* bSourceID */
    0x01,                                 /* bControlSize */
    AUDIO_CONTROL_MUTE,                   /* bmaControls(0) */
    0x00,                                 /* bmaControls(1) */
    0x00,                                 /* iTerminal */
    /* 09 byte*/

    /* Audio Control Output Terminal Descriptor - Speaker (UNIT ID 3 - Source ID 5) */
    0x09,                               /* bLength*/
    AUDIO_INTERFACE_DESCRIPTOR_TYPE,    /* bDescriptorType:CS_INTERFACE*/
    AUDIO_CONTROL_OUTPUT_TERMINAL,      /* bDescriptorSubType:OUTPUT_TERMINAL*/
    SPK_OT_ID,                          /* bTerminalID*/
    0x02,0x04,                          /* wTerminalType: Headset */
    SPK_IT_ID,                          /* bAssocTerminal*/
    SPK_FU_ID,                          /* bSourceID*/
    0x00,                               /* iTerminal*/
    /* 9 byte */
/* --------------- AudioStreaming Interface --------------- */
  /* USB Microphone Standard AS Interface Descriptor - Audio Streaming Zero Bandwith */
    /* Interface Descriptor - Interface 1, alternate 0 */
    AUDIO_INTERFACE_DESC_SIZE,            /* bLength */
    USB_INTERFACE_DESCRIPTOR_TYPE,        /* bDescriptorType */
    0x01,                                 /* bInterfaceNumber */
    0x00,                                 /* bAlternateSetting */
    0x00,                                 /* bNumEndpoints */
    USB_DEVICE_CLASS_AUDIO,               /* bInterfaceClass */
    AUDIO_SUBCLASS_AUDIOSTREAMING,        /* bInterfaceSubClass */
    AUDIO_PROTOCOL_UNDEFINED,             /* bInterfaceProtocol */
    0x00,                                 /* iInterface */
    /* 9 byte */
    
    /* USB Microphone Standard AS Interface Descriptor - Audio Streaming Operational */
    /* Interface Descriptor - Interface 1, alternate 1 */
    AUDIO_INTERFACE_DESC_SIZE,            /* bLength */
    USB_INTERFACE_DESCRIPTOR_TYPE,        /* bDescriptorType */
    0x01,                                 /* bInterfaceNumber */
    0x01,                                 /* bAlternateSetting */
    0x01,                                 /* bNumEndpoints */
    USB_DEVICE_CLASS_AUDIO,               /* bInterfaceClass */
    AUDIO_SUBCLASS_AUDIOSTREAMING,        /* bInterfaceSubClass */
    AUDIO_PROTOCOL_UNDEFINED,             /* bInterfaceProtocol */
    0x00,                                 /* iInterface */
    /* 9 byte */
    
    /* USB Microphone Class-specific AS General Interface Descriptor */
    AUDIO_STREAMING_INTERFACE_DESC_SIZE,  /* bLength */
    AUDIO_INTERFACE_DESCRIPTOR_TYPE,      /* bDescriptorType */
    AUDIO_STREAMING_GENERAL,              /* bDescriptorSubtype */
    MIC_OT_ID,                            /* bTernimalLink */
    0x01,                                 /* bDelay */
    0x01,0x00,                            /* wFormatTag:0x0001 PCM */
    /* 7 byte */

    /* USB Microphone Audio Type I Format Type Descriptor */
    0x0b,                                /* bLength */
    AUDIO_INTERFACE_DESCRIPTOR_TYPE,      /* bDescriptorType */
    AUDIO_STREAMING_FORMAT_TYPE,          /* bDescriptorSubtype */
    AUDIO_FORMAT_TYPE_I,                  /* bFormatType */
    0x02,                                 /* bNrChannels    :  2 Channels */
    0x03,                                 /* bSubFrameSize  :  3 bytes per sample */
    0x18,                                 /* bBitResolution : 24 bits  per sample */
    0x01,                                 /* bSamFreqType : 1*/
    SAMPLE_FREQ(USBD_AUDIO_FREQ),         /* tSamFreq : Audio sampling frequency coded on 3 bytes */
    /* 11 byte*/

    /* USB Microphone Standard AS Audio Data Endpoint Descriptor */
    AUDIO_STANDARD_ENDPOINT_DESC_SIZE,    /* bLength */
    USB_ENDPOINT_DESCRIPTOR_TYPE,         /* bDescriptorType */
    AUDIO_IN_EP,                          /* bEndpointAddress */
    0x05,                                 /* bmAttributes */
    /* wMaxPacketSize note */
    LOBYTE(AUDIO_IN_PACKET),              /* wMaxPacketSize */
    HIBYTE(AUDIO_IN_PACKET),
    0x01,                                 /* bInterval*/
    0x00,
    0x00,
    /* 09 byte*/
    
    /* USB Microphone Class-specific Isoc. Audio Data Endpoint Descriptor */
    AUDIO_STREAMING_ENDPOINT_DESC_SIZE,   /* bLength */
    AUDIO_ENDPOINT_DESCRIPTOR_TYPE,       /* bDescriptorType */
    AUDIO_ENDPOINT_GENERAL,               /* bDescriptor */
    0x01,                                 /* bmAttributes, Bit 0: Sampling Frequency */
    0x00,                                 /* bLockDelayUnits */
    0x00, 0x00,                           /* wLockDelay */
    /* 07 byte*/
    
//Speaker
    /* USB Speaker Standard AS Interface Descriptor - Audio Streaming Zero Bandwith */
    /* Interface 2, Alternate Setting 0                                             */
    AUDIO_INTERFACE_DESC_SIZE,            /* bLength */
    USB_INTERFACE_DESCRIPTOR_TYPE,        /* bDescriptorType */
    0x02,                                 /* bInterfaceNumber */
    0x00,                                 /* bAlternateSetting */
    0x00,                                 /* bNumEndpoints */
    USB_DEVICE_CLASS_AUDIO,               /* bInterfaceClass */
    AUDIO_SUBCLASS_AUDIOSTREAMING,        /* bInterfaceSubClass */
    AUDIO_PROTOCOL_UNDEFINED,             /* bInterfaceProtocol */
    0x00,                                 /* iInterface */
    /* 09 byte*/
    /* USB Speaker Standard AS Interface Descriptor - Audio Streaming Operational */
    /* Interface 2, Alternate Setting 1                                           */
    AUDIO_INTERFACE_DESC_SIZE,            /* bLength */
    USB_INTERFACE_DESCRIPTOR_TYPE,        /* bDescriptorType */
    0x02,                                 /* bInterfaceNumber */
    0x01,                                 /* bAlternateSetting */
    0x01,                                 /* bNumEndpoints */
    USB_DEVICE_CLASS_AUDIO,               /* bInterfaceClass */
    AUDIO_SUBCLASS_AUDIOSTREAMING,        /* bInterfaceSubClass */
    AUDIO_PROTOCOL_UNDEFINED,             /* bInterfaceProtocol */
    0x00,               /* iInterface */
    /* 09 byte*/

    /* USB Speaker Audio Streaming Interface Descriptor */
    AUDIO_STREAMING_INTERFACE_DESC_SIZE,  /* bLength */
    AUDIO_INTERFACE_DESCRIPTOR_TYPE,      /* bDescriptorType */
    AUDIO_STREAMING_GENERAL,              /* bDescriptorSubtype */
    SPK_IT_ID,                            /* bTernimalLink (Speaker) */
    0x01,                                 /* bDelay */
    0x01,0x00,                            /* wFormatTag:0x0001 PCM */
    /* 07 byte*/

    /* USB Speaker Audio Type I Format Interface Descriptor */
    0x0B,                                 /* bLength */
    AUDIO_INTERFACE_DESCRIPTOR_TYPE,      /* bDescriptorType */
    AUDIO_STREAMING_FORMAT_TYPE,          /* bDescriptorSubtype */
    AUDIO_FORMAT_TYPE_I,                  /* bFormatType */ 
    0x02,                                 /* bNrChannels    :  2 Channels */
    0x03,                                 /* bSubFrameSize  :  3 bytes per sample */
    0x18,                                 /* bBitResolution : 24 bits  per sample */
    0x01,                                 /* bSamFreqType : 1*/
    SAMPLE_FREQ(USBD_AUDIO_FREQ),         /* Audio sampling frequency coded on 3 bytes */
    /* 11 byte*/

    /* Endpoint 1 - Standard Descriptor */
    AUDIO_STANDARD_ENDPOINT_DESC_SIZE,    /* bLength */
    USB_ENDPOINT_DESCRIPTOR_TYPE,         /* bDescriptorType */
    AUDIO_OUT_EP,                         /* bEndpointAddress 1 out endpoint*/
    0x09,                                 /* bmAttributes */
    LOBYTE(AUDIO_OUT_PACKET),             /* wMaxPacketSize in Bytes (Freq(Samples)*2(Stereo)*2(HalfWord)) */
    HIBYTE(AUDIO_OUT_PACKET),
    0x01,                                 /* bInterval */
    0x00,                                 /* bRefresh */
    0x00,                                 /* bSynchAddress */
    /* 9 byte */
    /* Endpoint - Audio Streaming Descriptor*/
    AUDIO_STREAMING_ENDPOINT_DESC_SIZE,   /* bLength */
    AUDIO_ENDPOINT_DESCRIPTOR_TYPE,       /* bDescriptorType */
    AUDIO_ENDPOINT_GENERAL,               /* bDescriptor */
    0x01,                                 /* bmAttributes, Bit 7: MaxPacketsOnly, Bit 0: Sampling Frequency */
    0x01,                                 /* bLockDelayUnits */
    0x01, 0x00,                           /* wLockDelay */
    /* 7 byte */
} ;

/**
 *******************************************************************************
 ** \brief  initialize the interface of audio device
 ** \param  pdev: device instance
 ** \retval none
 ******************************************************************************/
void usb_dev_audio_init(void *pdev)
{  
    hd_usb_opendevep(pdev, AUDIO_OUT_EP, AUDIO_OUT_PACKET, USB_EP_ISOC);
    AUDIO_OUT_fops.Init( );
    hd_usb_readytorx(pdev, AUDIO_OUT_EP, (uint8_t*)IsocOutBuff, AUDIO_OUT_PACKET);  
    hd_usb_opendevep(pdev, AUDIO_IN_EP, AUDIO_IN_PACKET, USB_EP_ISOC);
    rec_state = REC_IDLE;
    AUDIO_IN_fops.Init( );    
}

/**
 *******************************************************************************
 ** \brief  deinitialize the interface of audio device
 ** \param  pdev: device instance
 ** \retval none
 ******************************************************************************/
void usb_dev_audio_deinit(void *pdev)
{ 
    hd_usb_shutdevep (pdev , AUDIO_OUT_EP);
    AUDIO_OUT_fops.DeInit( );
    hd_usb_shutdevep (pdev, AUDIO_IN_EP);
}

/**
 *******************************************************************************
 ** \brief  process the setup request of audio device
 ** \param  pdev: device instance
 ** \param  req: packet of setup request
 ** \retval status
 ******************************************************************************/
uint8_t usb_dev_audio_setup(void *pdev, USB_SETUP_REQ *req)
{
  uint16_t len=USB_AUDIO_DESC_SIZ;
  uint8_t  *pbuf=usbd_audio_CfgDesc + 18;
  
  switch (req->bmRequest & USB_REQ_TYPE_MASK)
  {
    /* AUDIO Class Requests -------------------------------*/
  case USB_REQ_TYPE_CLASS :    
    switch (req->bRequest)
    {
    case AUDIO_REQ_GET_CUR:
      audio_getcurrent_req(pdev, req);
      break;
      
    case AUDIO_REQ_SET_CUR:
      audio_setcurrent_req(pdev, req);   
      break;

    default:
      hd_usb_ctrlerr (pdev);
      return USBD_FAIL;
    }
    break;
    
    /* Standard Requests -------------------------------*/
  case USB_REQ_TYPE_STANDARD:
    switch (req->bRequest)
    {
    case USB_REQ_GET_DESCRIPTOR: 
      if( (req->wValue >> 8) == AUDIO_DESCRIPTOR_TYPE)
      {
        pbuf = usbd_audio_CfgDesc + 18;
        len = MIN(USB_AUDIO_DESC_SIZ , req->wLength);
      }
      
      hd_usb_ctrldatatx (pdev, 
                        pbuf,
                        len);
      break;
      
    case USB_REQ_GET_INTERFACE :
      hd_usb_ctrldatatx (pdev,
                        (uint8_t *)&usbd_audio_AltSet,
                        1);
      break;
      
    case USB_REQ_SET_INTERFACE :
      if ((uint8_t)(req->wValue) < 3)
      {
        usbd_audio_AltSet = (uint8_t)(req->wValue);
        if (usbd_audio_AltSet == 1)
        {
            RecFlag = 1;
        }
        else
        {
            RecFlag = 0;
            hd_usb_flsdevep(pdev, AUDIO_IN_EP);
        }        
      }
      else
      {
        hd_usb_ctrlerr (pdev);
      }
      break;
    }
  }
  return USBD_OK;
}

/**
 *******************************************************************************
 ** \brief  process the receive data of the control out EP
 ** \param  pdev: device instance
 ** \retval none
 ******************************************************************************/
void usb_dev_audio_ctrlout(void *pdev)
{ 
  /* Check if an AudioControl request has been issued */
  if (AudioCtlCmd == AUDIO_REQ_SET_CUR)
  {/* In this driver, to simplify code, only SET_CUR request is managed */
    /* Check for which addressed unit the AudioControl request has been issued */
    if (AudioCtlUnit == AUDIO_OUT_STREAMING_CTRL)
    {/* In this driver, to simplify code, only one unit is manage */
      /* Call the audio interface mute function */
      AUDIO_OUT_fops.MuteCtl(AudioCtl[0]);
      
      /* Reset the AudioCtlCmd variable to prevent re-entering this function */
      AudioCtlCmd = 0;
      AudioCtlLen = 0;
    }
  } 
}

/**
 *******************************************************************************
 ** \brief  process the data of in EP
 ** \param  pdev: device instance
 ** \retval none
 ******************************************************************************/
uint8_t txbuf[AUDIO_IN_PACKET];
void Data_In_Process(void *pdev)
{
    uint16_t tmp, tmp1;
    uint8_t tmp2;
    if(rec_state == REC_RUN)
    {
        tmp1 = 0;
        for(tmp = 0; tmp < AUDIO_IN_SAMPLE_NUM; tmp++)
        {
            /* Get the bit0-bit7, bit8-bit15 and bit16-bit23 of IsiocInWrPtr[tmp]
                                 for txbuf[tmp2], txbuf[tmp2+1] and txbuf[tmp2+2] */
            for(tmp2 = 0; tmp2 < 3; tmp2++)
            {
                txbuf[tmp1++] = (IsocInWrPtr[tmp]>>(tmp2*8))&0xff;
            }
        }
        hd_usb_deveptx(pdev, AUDIO_IN_EP, (uint8_t*)txbuf, AUDIO_IN_PACKET);
        IsocInWrPtr += AUDIO_IN_SAMPLE_NUM;
        if(IsocInWrPtr>= (IsocInBuff+(AUDIO_IN_SAMPLE_NUM * IN_PACKET_NUM)))
        {
            IsocInWrPtr = IsocInBuff;     //Re-equate the start address of IsocInBuff to IsiocInWrPtr
        }
    }    
    if(rec_state == REC_IDLE || rec_state == REC_STOP)
    {
        if(IsocInRdCnt == 0)
        {
            /* Make the I2s Start to record */
            AUDIO_IN_fops.AudioCmd((uint8_t *)IsocInBuff,                          /* Samples buffer pointer */
                                   AUDIO_IN_SAMPLE_NUM,                                /* Number of samples in WORD */
                                   AUDIO_IN_CMD_START);                            /* Command to be processed */             
        }
        /* If the IsocInBuff is haft full then change the rec_state value */
        if(IsocInRdCnt>= (IN_PACKET_NUM>>1))  
        {
            rec_state = REC_RUN;
        }
        hd_usb_deveptx(pdev, AUDIO_IN_EP, (uint8_t*)InBuffDummy, AUDIO_IN_PACKET);
    }
}

/**
 *******************************************************************************
 ** \brief  process the data on the IN EP
 ** \param  pdev: device instance
 ** \param  epnum: endpoint number of IN EP
 ** \retval none
 ******************************************************************************/
void usb_dev_audio_datain(void *pdev, uint8_t epnum)
{  
    if(epnum == (AUDIO_IN_EP & 0x7F))
    {
        hd_usb_flsdevep(pdev, AUDIO_IN_EP);
        /* Toggle the frame index */
        ((usb_core_instance*)pdev)->dev.in_ep[epnum].datax_pid = \
                             (((usb_core_instance*)pdev)->dev.in_ep[epnum].datax_pid)? 0:1; 
        Data_In_Process(pdev);        
        in_exit = 0;
    }
}

/**
 *******************************************************************************
 ** \brief  process the data on the OUT EP
 ** \param  pdev: device instance
 ** \param  epnum: endpoint number of OUT EP
 ** \retval none
 ******************************************************************************/
void Data_Out_Process(void *pdev, uint8_t epnum)
{
  if (epnum == AUDIO_OUT_EP)
  {    
    /* Increment the Buffer pointer or roll it back when all buffers are full */
    if (IsocOutWrPtr >= (IsocOutBuff + (AUDIO_OUT_PACKET * OUT_PACKET_NUM)))
    {/* All buffers are full: roll back */
      IsocOutWrPtr = IsocOutBuff;
    }
    else
    {/* Increment the buffer pointer */
      IsocOutWrPtr += AUDIO_OUT_PACKET;
    }
    
    /* Toggle the frame index */  
    ((usb_core_instance*)pdev)->dev.out_ep[epnum].datax_pid = 
      (((usb_core_instance*)pdev)->dev.out_ep[epnum].datax_pid)? 0:1;
      
    /* Prepare Out endpoint to receive next audio packet */
    hd_usb_readytorx(pdev,
                     AUDIO_OUT_EP,
                     (uint8_t*)(IsocOutWrPtr),
                     AUDIO_OUT_PACKET);
      
    /* Trigger the start of streaming only when half buffer is full */
    if ((PlayFlag == 0) && (IsocOutWrPtr >= (IsocOutBuff + ((AUDIO_OUT_PACKET * OUT_PACKET_NUM) / 2))))
    {
      /* Enable start of Streaming */
      PlayFlag = 1;
    }
  }    
}

/**
 *******************************************************************************
 ** \brief  process the data on the OUT EP
 ** \param  pdev: device instance
 ** \param  epnum: endpoint number of OUT EP
 ** \retval none
 ******************************************************************************/
void usb_dev_audio_dataout(void *pdev, uint8_t epnum)
{     
    data_out_flag = 1;
}

/**
 *******************************************************************************
 ** \brief  process the SOF of audio device
 ** \param  pdev: device instance
 ** \retval none
 ******************************************************************************/
void Sof_Process(void *pdev)
{
  /* Check if there are available data in stream buffer.
    In this function, a single variable (PlayFlag) is used to avoid software delays.
    The play operation must be executed as soon as possible after the SOF detection. */
  if (PlayFlag)
  {      
    /* Start playing received packet */
    AUDIO_OUT_fops.AudioCmd((uint8_t*)(IsocOutRdPtr),  /* Samples buffer pointer */
                            AUDIO_OUT_PACKET,          /* Number of samples in Bytes */
                            AUDIO_CMD_PLAY);           /* Command to be processed */
    
    /* Increment the Buffer pointer or roll it back when all buffers all full */  
    if (IsocOutRdPtr >= (IsocOutBuff + (AUDIO_OUT_PACKET * OUT_PACKET_NUM)))
    {/* Roll back to the start of buffer */
      IsocOutRdPtr = IsocOutBuff;
    }
    else
    {/* Increment to the next sub-buffer */
      IsocOutRdPtr += AUDIO_OUT_PACKET;
    }
    
    /* If all available buffers have been consumed, stop playing */
    if (IsocOutRdPtr == IsocOutWrPtr)
    {    
      /* Pause the audio stream */
      AUDIO_OUT_fops.AudioCmd((uint8_t*)(IsocOutBuff),   /* Samples buffer pointer */
                              AUDIO_OUT_PACKET,          /* Number of samples in Bytes */
                              AUDIO_CMD_PAUSE);          /* Command to be processed */
      
      /* Stop entering play loop */
      PlayFlag = 0;     
      /* Reset buffer pointers */
      IsocOutRdPtr = IsocOutBuff;
      IsocOutWrPtr = IsocOutBuff;
    }
  }
      
}

/**
 *******************************************************************************
 ** \brief  process the SOF of audio device
 ** \param  pdev: device instance
 ** \retval status
 ******************************************************************************/
uint8_t usb_dev_audio_sof(void *pdev)
{     
    sof_flag = 1;
	if (RecFlag == 1)
	{
		hd_usb_deveptx(pdev, AUDIO_IN_EP, NULL, 0);
		RecFlag = 0;        
	}
    if(rec_state == REC_RUN)
    {
        in_exit++;
        if(in_exit>5)
        {
            in_exit = 0;
            rec_state = REC_STOP;
            IsocInRdCnt = 0;
            IsocInWrCnt = 0;
            IsocInRdPtr = IsocInBuff;
            IsocInWrPtr = IsocInBuff;
            AUDIO_IN_fops.AudioCmd((uint8_t*)IsocInBuff,                                     /* Samples buffer pointer */
                                   AUDIO_IN_PACKET>>1,                             /* Number of samples in Bytes */
                                   AUDIO_IN_CMD_STOP);                             /* Command to be processed */        
        }
    }        
    return USBD_OK;
}

/**
 *******************************************************************************
 ** \brief  process the iso IN incomplete event
 ** \param  pdev: device instance
 ** \retval none
 ******************************************************************************/
void usb_dev_audio_in_incplt(void *pdev)
{
    USB_CORE_DSTS_TypeDef dsts;
    __IO USB_CORE_DEPCTL_TypeDef depctl;
    usb_core_instance *ppdev = pdev;
    dsts.d32 = HD_USB_RDREG32(&ppdev->regs.DREGS->DSTS);
    depctl.d32  = HD_USB_RDREG32(&ppdev->regs.INEP_REGS[AUDIO_IN_EP & 0x7F]->DIEPCTL);
  /* Check if this is the first packet */
    if (((dsts.b.soffn) & 1) == depctl.b.dpid)
    {      
        /* EP disable */       
        depctl.b.snak = 1;
        depctl.b.epdis = 1;
        HD_USB_WRREG32(&ppdev->regs.INEP_REGS[AUDIO_IN_EP & 0x7F]->DIEPCTL, depctl.d32);

        /* Flush endpoint */
        hd_usb_flsdevep(pdev, AUDIO_IN_EP);
        if(rec_state == REC_RUN)
        {
            hd_usb_deveptx(pdev, AUDIO_IN_EP, (uint8_t*)txbuf, AUDIO_IN_PACKET);
        }
        else
        {
            hd_usb_deveptx(pdev, AUDIO_IN_EP, (uint8_t*)InBuffDummy, AUDIO_IN_PACKET);
        }
    }       
}

/**
 *******************************************************************************
 ** \brief  process the iso OUT incomplete event
 ** \param  pdev: device instance
 ** \retval none
 ******************************************************************************/
void usb_dev_audio_out_incplt(void *pdev)
{
    //TODO
}

/**
 *******************************************************************************
 ** \brief  process the GET_CUR of the audio control request
 ** \param  pdev: device instance
 ** \param  req: packet of setup
 ** \retval none
 ******************************************************************************/
void audio_getcurrent_req(void *pdev, USB_SETUP_REQ *req)
{  
    // Send the current mute state to the host
    hd_usb_ctrldatatx (pdev, AudioCtl, req->wLength);
}

/**
 *******************************************************************************
 ** \brief  process the SET_CUR of the audio control request
 ** \param  pdev: device instance
 ** \param  req: packet of setup
 ** \retval none
 ******************************************************************************/
void audio_setcurrent_req(void *pdev, USB_SETUP_REQ *req)
{ 
    if (req->wLength)
    {
        // Prepare the reception of the buffer over EP0
        hd_usb_ctrldatarx (pdev, AudioCtl, req->wLength);

        /* Set the global variables indicating current request and its length 
        to the function usb_dev_audio_ctrlout() which will process the request */
        AudioCtlCmd = AUDIO_REQ_SET_CUR;     // Set the request value
        AudioCtlLen = req->wLength;          // Set the request data length 
        AudioCtlUnit = HIBYTE(req->wIndex);  // Set the request target unit 
        AudioTrgtEpt = LOBYTE(req->wIndex);  // Set the request target endpoint   
    }
}

/**
 *******************************************************************************
 ** \brief  get the configuration descriptor
 ** \param  length: length in bytes of the configuration descriptor
 ** \retval pointer of configuration descriptor
 ******************************************************************************/
uint8_t *usb_dev_audio_getcfgdesc(uint16_t *length)
{
    *length = sizeof (usbd_audio_CfgDesc);
    return usbd_audio_CfgDesc;
}

